package svmClassifier;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;

import libsvm.svm;
import libsvm.svm_model;
import libsvm.svm_node;
import maxEntClassifier.Classifier;
import maxEntClassifier.U;

import featureSelection.FeatureSelection;

public class SVMClassifier extends Classifier {
	
	HashMap<String,Integer> wordMap;
	svm_model model ;

	public SVMClassifier(String _trainSet,String _testSet,HashSet<String> featureSet) throws IOException {
		super(_trainSet, _testSet);
		modelFile = "./out/svm_model.txt";
		testOut = "./out/svm_testOut.txt";
		
		wordMap =featureSet2WordMap(featureSet);
		SVMClassifier.outcomeNames=getOutLabels(trainSet);
		
	}

	@Override
	public String inference(String[] features) throws IOException {
		
		svm_node[] x = new svm_node[wordMap.size()];
		for(int j=0;j<wordMap.size();j++)
		{
			x[j] = new svm_node();
			x[j].index = j;
			x[j].value = 0;
		}
		
		boolean empty=true;
		for(String word:features){
			if(wordMap.get(word)==null)continue;
			x[wordMap.get(word)].value=1;
			empty=false;
		}
		if(empty)
			return null;
		
		int output = (int) svm.svm_predict(model,x);
		return outcomeNames[(output)]; 
		}

	@Override
	public void loadModel() throws IOException {
		model = svm.svm_load_model(modelFile);
	}

	@Override
	public void train() throws FileNotFoundException, IOException {
		String svmTrainFile="./out/svmTrain.txt";
		toSVMDataFile(trainSet,svmTrainFile,wordMap,SVMClassifier.outcomeNames);
		svm_train t =new svm_train();
		t.run(svmTrainFile, modelFile);
	}
	
	public static void main() throws Exception {
		String trainSet="./out/a.txt";
		FeatureSelection fs = new FeatureSelection(trainSet);
		FeatureSelection.ratio =1;
		HashSet<String> featureSet = fs.multiSortFeatureSelection();
		
		HashMap<String,Integer> map =featureSet2WordMap(featureSet);
		SVMClassifier.outcomeNames=getOutLabels(trainSet);
		toSVMDataFile(trainSet,"./out/b.txt",map,SVMClassifier.outcomeNames);
		System.out.println();
	}
	
	public static void main(String[] args) throws Exception {
		
		FeatureSelection.ratio = 0.05;
		FeatureSelection.featureCount = -1;
		String dataSetDir = "./data/webkb/";
		
		String trainSet=dataSetDir+"train.txt";
		String testSet=dataSetDir+"test.txt";
		


		FeatureSelection fs = new FeatureSelection(trainSet);

		HashSet<String> featureSet = fs.multiSortFeatureSelection();
		
		
		SVMClassifier classifier=new SVMClassifier(trainSet, testSet,featureSet);
		//classifier.train();
		classifier.test();

	}

	private static String[] getOutLabels(String trainSet) throws IOException {
		HashSet<String> labels =new HashSet<String>();
		BufferedReader r =U.newReader(trainSet);
		while (true) {
			String l =r.readLine();
			if(null==l) break;
			String[] sa =l.split(" ");
			labels.add(sa[sa.length-1]);
		}
		r.close();
		return U.set2Sa(labels);
	}

	private static HashMap<String, Integer> featureSet2WordMap(
			HashSet<String> featureSet) {
		HashMap<String, Integer> res =new HashMap<String, Integer>();
		
		int i =0;
		for(String f :featureSet){
			String p =U.getFP(f);
			if (res.containsKey(p)) continue;
			res.put(p, i);
			i++;
		}
		return res;
	}

	private static void toSVMDataFile(String in , String out,
			HashMap<String,Integer> map,String[] outLabels) throws IOException {
			BufferedReader r =U.newReader(in);
			BufferedWriter w =U.newWriter(out);
			while (true) {
				String l =r.readLine();
				if(null==l) break;
				String[] sa=l.split(" ");
				int label = U.getIndex(SVMClassifier.outcomeNames, sa[sa.length-1]);
				int[] context =new int[map.size()];
				for(int i =0;i<sa.length-1;i++){
					if(map.get(sa[i])==null)continue;
					context[map.get(sa[i])]=1;
				}
				String nl =""+label;
				for(int i =0;i<context.length;i++){
					nl+= " "+i+":"+context[i];
				}
				w.write(nl+"\n");
			}
			r.close();
			w.close();
			
		
	}

}
